#pragma once


namespace Melting
{
namespace Parallel
{
	//--------------------------------------------------------------------------------------------------------------------
#ifdef WIN32
    typedef volatile INT32		SpinLockHandle;
#else
    typedef pthread_spinlock_t	SpinLockHandle;
#endif

	//--------------------------------------------------------------------------------------------------------------------
	class SpinLock
    {
    public:
		inline SpinLock( void );
        inline ~SpinLock( void );

		/// Try to lock (only 1 try) - returns true if successful 
        inline bool		TryLock( void );
		
		/// Lock (infinite retries)
        inline void		Lock( void );
		
		/// Unlock the SpinLock
        inline void		Unlock( void );

		inline bool IsLocked( void ) const;

    private:
        SpinLockHandle mHandle;
    };

#ifdef WIN32
	//----------------------------------------------------------------
	//----------------------------------------------------------------
    SpinLock::SpinLock( void )
    : mHandle( 0 )
    {
    }
	//----------------------------------------------------------------
	//----------------------------------------------------------------
    SpinLock::~SpinLock( void )
    {
    }
	//----------------------------------------------------------------
	//----------------------------------------------------------------
	bool SpinLock::IsLocked( void ) const
	{
		return 1 == mHandle;
	}
	//----------------------------------------------------------------
	//----------------------------------------------------------------
    bool SpinLock::TryLock( void )
    {
		SpinLockHandle handle = AtomicCompareAndSwap( & mHandle, 1, 0 );

		MemoryBarrier();

        return 0 == handle;
    } 
	//----------------------------------------------------------------
	//----------------------------------------------------------------
    void SpinLock::Lock( void )
    {
        while( AtomicCompareAndSwap( & mHandle, 1, 0 ) )
        {
//	        MemoryBarrier(); 

			YieldProcessor();
            ;// try again !
        }
        // We got it !
//        MemoryBarrier(); 
    } 
	//----------------------------------------------------------------
	//----------------------------------------------------------------
    void SpinLock::Unlock( void )
    {
        MemoryBarrier();

        mHandle = 0;
    }

#else // PTHREAD 
	//----------------------------------------------------------------
	//----------------------------------------------------------------
    SpinLock::SpinLock( void )
    : mHandle()
    {
        INT32 iResult = pthread_spin_init( & mHandle, nullptr );
        MB_ASSERT( 0 == iResult );
    }
	//----------------------------------------------------------------
	//----------------------------------------------------------------
    SpinLock::~SpinLock( void )
    {
        INT32 iResult = pthread_spin_destroy( & mHandle );
        MB_ASSERT( 0 == iResult );
    }
	//----------------------------------------------------------------
	//----------------------------------------------------------------
	bool SpinLock::TryLock()
	{
		return 0 == pthread_spin_trylock( & mHandle );
	}
	//----------------------------------------------------------------
	//----------------------------------------------------------------
    void SpinLock::Lock( void )
    {
		INT32 iResult = pthread_spin_lock( &mHandle );
        MB_ASSERT( 0 == iResult );
    }
	//----------------------------------------------------------------
	//----------------------------------------------------------------
    void SpinLock::Unlock( void )
    {
		INT32 iResult = pthread_spin_unlock( &mHandle );
        MB_ASSERT( 0 == iResult );
    }
#endif 
}
}// namespace Melting